#pragma once 

#include<iostream>
#include<string>
#include<fstream>
#include<vector>
#include<sstream>
#include<unordered_map>

#include"Socket.hpp"
#include"Log.hpp"

const std::string wwwroot = "./wwwroot";
const std::string seq = "\r\n";
const std::string homepage = "index.html";

static const int defaultport = 8082;

class HttpServer;

class ThreadData{
public:
    ThreadData(int fd, HttpServer *s):sockfd(fd),svr(s){
        
    }
public:
    int sockfd;
    HttpServer *svr;
};

class HttpRequest{
public:
    void Deserialize(std::string req){//解序列化
        while(true){
            std::size_t pos = req.find(seq);
            if(pos == std::string::npos) break;
            std::string temp = req.substr(0,pos);
            if(temp.empty()) break;
            req_header.push_back(temp);
            req.erase(0,pos+seq.size());//删除报头
        }
        text = req;
    }

    void Parse(){
        std::stringstream ss(req_header[0]);
        ss>>method>>url>>http_version;
        file_path = wwwroot;
        if(url=="/" || url == "/index.html"){
            file_path += "/";
            file_path += homepage;    
        }
        else file_path += url;
        
        auto pos=file_path.rfind(".");//找不到
        if(pos == std::string::npos) suffix = ".html";
        else suffix = file_path.substr(pos);//返回.xxx
    }
    
    void DebugPrint(){
        for(auto &line : req_header){
            std::cout<<"-------------------------------"<<std::endl;
            std::cout<<line<<std::endl;
        }
        std::cout<<"method:"<<method<<std::endl;
        std::cout<<"url: "<<url<<std::endl;
        std::cout<<"http_version:"<<http_version<<std::endl;
        std::cout << "file_path: " << file_path << std::endl;
        std::cout << text << std::endl;
    }
public:
    std::vector<std::string> req_header;
    std::string text;

    //解析后的结果
    std::string method;
    std::string url;
    std::string http_version;
    std::string file_path;
    
    std::string suffix;
};

class HttpServer{
public:
    HttpServer(uint16_t port = defaultport):port_(port){
        content_type.insert({".html","text/html"});
        content_type.insert({".png","image/png"});
    }

    bool Start(){
        listensock_.Socket();
        listensock_.Bind(port_);
        listensock_.Listen();
        while(1){
            std::string clientip;
            uint16_t clientport;
            int sockfd = listensock_.Accept(&clientip,&clientport);
            if(sockfd<0){
                lg(Info,"get a new connect, sockfd: %d",sockfd);
                continue;
            }
            lg(Info,"get a new connect, sockfd: %d",sockfd);
            pthread_t tid;
            ThreadData *td = new ThreadData(sockfd,this);
            pthread_create(&tid,nullptr,ThreadRun,td);
        }
    }
    
    static std::string ReadHtmlContent(const std::string &htmlpath){
        std::ifstream in(htmlpath, std::ios::binary);//读取文件
        if(!in.is_open()) return "";
        
        in.seekg(0,std::ios_base::end);
        auto len=in.tellg();//in的长度
        in.seekg(0,std::ios_base::beg);

        std::string content;
        content.resize(len);
        
        in.read((char*)content.c_str(),content.size());
        in.close();
        return content;
    }

    std::string suffixToDesc(const std::string &suffix){
        auto iter = content_type.find(suffix);
        if(iter == content_type.end()) return content_type[".html"];
        else return content_type[suffix];
    }

    void HandlerHttp(int sockfd){
        char buffer[10240];
        ssize_t n = recv(sockfd,buffer,sizeof(buffer)-1,0);
        if(n>0){
            buffer[n] = 0;
            std::cout<<buffer<<std::endl;
            HttpRequest req;
            req.Deserialize(buffer);
            req.Parse();

            std::string text;
            bool ok = true;
            text = ReadHtmlContent(req.file_path);//读取文件
            if(text.empty()){
                ok = false;
                std::string err_html = wwwroot;
                err_html += "/";
                
            }
            std::string  response_line;
            if(ok)
                response_line = "HTTP/1.0 200 OK\r\n";
            else
                response_line = "HTTP/1.0 404 Not Found\r\n";

            std::string response_header = "content-Length:";
            response_header += std::to_string(text.size());
            response_header += "\r\n";
            response_header += "Content-Type: ";
            response_header += suffixToDesc(req.suffix);
            response_header += "\r\n";
            response_header += "set-Cookie: name=haha&&passwd=12345";
            response_header += "\r\n";

            std::string blank_line = "\r\n";//之前的是报头

            std::string response = response_line;
            response += response_header;
            response += blank_line;
            response += text;
            
            send(sockfd, response.c_str(),response.size(),0);
        }
        close(sockfd);
    }
    static void *ThreadRun(void *args){
        pthread_detach(pthread_self());
        ThreadData *td = static_cast<ThreadData *>(args);
        td->svr->HandlerHttp(td->sockfd);
        delete td;
        return nullptr;
    }
    ~HttpServer(){
    }
private:
    Sock listensock_;
    uint16_t port_;
    std::unordered_map<std::string, std::string> content_type;
};


